/**
 * @file ebex_genetic_select.h
 *
 * @date Oct 21, 2011
 * @author seth
 *
 * @brief This file is part of EBEX State Estimator, created for the EBEX project
 *
 * This software is copyright (C) 2011 Columbia University
 *
 * EBEX State Estimator is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * EBEX State Estimator is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EBEX State Estimator; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <ebex_genetic.h>

#include <ebex_genetic_select.h>

static bool ebex_genetic_select_stats(population_t *m_pop, double *m_mu, double *m_sigma, double *m_sum)
{
	size_t i;
	double sum = 0.0;
	double sumsq = 0.0;

	for (i = 0; i < m_pop->orig_size; i++)
	{
		sum += m_pop->sorted_organisms[i]->fitness;
		sumsq += (m_pop->sorted_organisms[i]->fitness * m_pop->sorted_organisms[i]->fitness);
	}

	*m_sum = sum;
	*m_mu = sum / m_pop->orig_size;
	*m_sigma = (sumsq - sum * sum / m_pop->orig_size) / m_pop->orig_size;

	return true;
}

static double ebex_genetic_select_sum_fitness(population_t *m_pop)
{
	size_t i;
	double sum = 0.0;

	for (i = 0; i < m_pop->orig_size; i++)
	{
		sum += m_pop->sorted_organisms[i]->fitness;
	}

	return sum;
}

static double ebex_genetic_select_sum_sq_fitness(population_t *m_pop)
{
	size_t i;
	double sum = 0.0;

	for (i = 0; i < m_pop->orig_size; i++)
	{
		sum += (m_pop->sorted_organisms[i]->fitness * m_pop->sorted_organisms[i]->fitness );
	}

	return sum;
}

/**
 * Select single, random organism.  Select finishes when num = pop_size * mutatation_ratio
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_random(population_t *m_pop, organism_t **m_parent)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	if (m_pop->orig_size < 1)
	{
		*m_parent = NULL;
		return true;
	}

	*m_parent = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	m_pop->select_state++;

	return m_pop->select_state > (m_pop->orig_size * m_pop->mutation_ratio);
}

static bool ebex_genetic_select_two_random(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	if (m_pop->orig_size < 2)
	{
		*m_mother = NULL;
		*m_father = NULL;
		return true;
	}

	*m_mother = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	do
	{
		*m_father = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	} while (*m_mother == *m_father);

	m_pop->select_state++;

	return m_pop->select_state > (m_pop->orig_size * m_pop->crossover_ratio);
}


static bool ebex_genetic_select_one_every(population_t *m_pop, organism_t **m_parent)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_parent = NULL;

	if (m_pop->orig_size <= m_pop->select_state)
	{
		return true;
	}

	*m_parent = m_pop->sorted_organisms[m_pop->select_state];

	m_pop->select_state++;

	return false;
}

/**
 * Selects every possible pair of parents, one at a time
 * @param m_pop Population pointer
 * @param m_mother First individual
 * @param m_father Second individual
 * @return True if full selection is complete, False otherwise
 */
static bool ebex_genetic_select_two_every(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_mother = NULL;
	*m_father = NULL;

	if ((m_pop->orig_size * m_pop->orig_size) <= m_pop->select_state)
	{
		return true;
	}

	*m_mother = m_pop->sorted_organisms[m_pop->select_state % m_pop->orig_size];
	*m_father = m_pop->sorted_organisms[m_pop->select_state / m_pop->orig_size];

	m_pop->select_state++;

	return false;
}

/**
 * Select a random organism, weighting the fitter organisms higher
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_randomrank(population_t *m_pop, organism_t **m_parent)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_parent = NULL;

	if (m_pop->orig_size < m_pop->select_state)
	{
		return true;
	}

	if (ran_bool_prob(m_pop->mutation_ratio))
	{
		*m_parent = m_pop->sorted_organisms[ran_uint_uniform(m_pop->select_state)];
	}

	return false;
}

/**
 * Select a pair of organisms, for each father, select a random, fitter mother
 * @param m_pop
 * @param m_mother
 * @param m_father
 * @return
 */
static bool ebex_genetic_select_two_randomrank(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_mother = NULL;
	*m_father = NULL;

	if (m_pop->orig_size < m_pop->select_state)
	{
		return true;
	}

	if (ran_bool_prob(m_pop->crossover_ratio))
	{
		*m_mother = m_pop->sorted_organisms[ran_uint_uniform(m_pop->select_state)];
		*m_father = m_pop->sorted_organisms[m_pop->select_state];
	}

	return false;
}

/**
 * Tournament selection.  Take 3 random entries and return the fittest.
 * Stops when total selected >= population_size * mutation_ratio
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_bestof3(population_t *m_pop, organism_t **m_parent)
{
	organism_t *mother2, *mother3; /* Random competitors. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	if (m_pop->orig_size < 1)
	{
		*m_parent = NULL;
		return true;
	}

	*m_parent = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	mother2 = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	mother3 = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	if (mother2->fitness > (*m_parent)->fitness)
		*m_parent = mother2;
	if (mother3->fitness > (*m_parent)->fitness)
		*m_parent = mother3;

	m_pop->select_state++;

	return m_pop->select_state > (m_pop->orig_size * m_pop->mutation_ratio);
}

/**
 * Tournament selection.  Take 3 random entries and return the fittest 2.
 * These are guaranteed to not be the same entity
 * Stops when total selected >= population_size * mutation_ratio
 * @param m_pop
 * @param m_mother
 * @param m_father
 * @return
 */
static bool ebex_genetic_select_two_bestof3(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{
	organism_t *challenger1, *challenger2; /* Random competitors. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	if (m_pop->orig_size < 2)
	{
		*m_mother = NULL;
		*m_father = NULL;
		return true;
	}

	*m_mother = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	challenger1 = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	challenger2 = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	if (challenger1->fitness > (*m_mother)->fitness)
		*m_mother = challenger1;
	if (challenger2->fitness > (*m_mother)->fitness)
		*m_mother = challenger2;

	do
	{
		*m_father = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	} while (*m_mother == *m_father);

	challenger1 = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	challenger2 = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	if (challenger1 != *m_mother && challenger1->fitness > (*m_father)->fitness)
		*m_father = challenger1;

	if (challenger2 != *m_mother && challenger2->fitness > (*m_father)->fitness)
		*m_father = challenger2;

	m_pop->select_state++;

	return m_pop->select_state > (m_pop->orig_size * m_pop->crossover_ratio);
}

/**
 * Tournament selection.  Take 2 random entries and return the fittest.
 * Stops when total selected >= population_size * mutation_ratio
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_bestof2(population_t *m_pop, organism_t **m_parent)
{
	organism_t *alternate;

	if (!m_pop)
		die("Null pointer to population structure passed.");

	if (m_pop->orig_size < 1)
	{
		*m_parent = NULL;
		return true;
	}

	*m_parent = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	alternate = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	if (alternate->fitness > (*m_parent)->fitness)
		*m_parent = alternate;

	m_pop->select_state++;

	return m_pop->select_state > (m_pop->orig_size * m_pop->mutation_ratio);
}


static bool ebex_genetic_select_two_bestof2(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{
	organism_t *challenger; /* Random competitor. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	if (m_pop->orig_size < 2)
	{
		*m_mother = NULL;
		*m_father = NULL;
		return true;
	}

	*m_mother = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	challenger = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	if (challenger->fitness > (*m_mother)->fitness)
		*m_mother = challenger;

	do
	{
		*m_father = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	} while (*m_mother == *m_father);

	challenger = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];

	if (challenger != *m_mother && challenger->fitness > (*m_father)->fitness)
		*m_father = challenger;

	m_pop->select_state++;

	return m_pop->select_state > (m_pop->orig_size * m_pop->crossover_ratio);
}


/**
 * Roulette selection based on John Holland's selection mechanism.
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_roulette(population_t *m_pop, organism_t **m_parent)
{
	double selectval; /* Select when this reaches zero. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_parent = NULL;

	if (m_pop->orig_size < 1 || m_pop->select_state + 1 > (m_pop->orig_size * m_pop->mutation_ratio))
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		ebex_genetic_select_stats(m_pop, &(m_pop->selectdata.mean), &(m_pop->selectdata.stddev), &(m_pop->selectdata.sum));
		m_pop->selectdata.current_expval = m_pop->selectdata.sum / m_pop->selectdata.mean;
		m_pop->selectdata.marker = ran_uint_uniform(m_pop->orig_size);
	}

	selectval = ran_double(m_pop->selectdata.current_expval) * m_pop->selectdata.mean;

	do
	{
		m_pop->selectdata.marker++;

		if (m_pop->selectdata.marker >= m_pop->orig_size)
			m_pop->selectdata.marker = 0;

		selectval -= m_pop->sorted_organisms[m_pop->selectdata.marker]->fitness;

	} while (selectval > 0.0);

	m_pop->select_state++;

	*m_parent = m_pop->sorted_organisms[m_pop->selectdata.marker];

	return false;
}


static bool ebex_genetic_select_one_roulette_rebased(population_t *m_pop, organism_t **m_parent)
{
	double selectval; /* Select when this reaches zero. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_parent = NULL;

	if (m_pop->orig_size < 1 || m_pop->select_state + 1 > (m_pop->orig_size * m_pop->mutation_ratio))
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		ebex_genetic_select_stats(m_pop, &(m_pop->selectdata.mean), &(m_pop->selectdata.stddev), &(m_pop->selectdata.sum));
		m_pop->selectdata.marker = ran_uint_uniform(m_pop->orig_size);
		m_pop->selectdata.minval = m_pop->sorted_organisms[m_pop->orig_size - 1]->fitness;
		m_pop->selectdata.mean -= m_pop->selectdata.minval;
		if (ISDBL_TINY(m_pop->selectdata.mean))
			die("Degenerate population?");
		m_pop->selectdata.current_expval = (m_pop->selectdata.sum - m_pop->selectdata.minval * m_pop->orig_size)
				/ m_pop->selectdata.mean;
	}

	selectval = ran_double(m_pop->selectdata.current_expval);

	do
	{
		m_pop->selectdata.marker++;

		if (m_pop->selectdata.marker >= m_pop->orig_size)
			m_pop->selectdata.marker = 0;

		selectval -= (m_pop->sorted_organisms[m_pop->selectdata.marker]->fitness - m_pop->selectdata.minval)
				/ m_pop->selectdata.mean;

	} while (selectval > 0.0);

	m_pop->select_state++;

	*m_parent = m_pop->sorted_organisms[m_pop->selectdata.marker];

	return false;
}


static bool ebex_genetic_select_two_roulette(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{
	double selectval; /* Select when this reaches zero. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_mother = NULL;
	*m_father = NULL;

	if (m_pop->orig_size < 1 || m_pop->select_state + 1 > (m_pop->orig_size * m_pop->mutation_ratio))
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		ebex_genetic_select_stats(m_pop, &(m_pop->selectdata.mean), &(m_pop->selectdata.stddev), &(m_pop->selectdata.sum));
		m_pop->selectdata.current_expval = m_pop->selectdata.sum / m_pop->selectdata.mean;
		m_pop->selectdata.marker = ran_uint_uniform(m_pop->orig_size);
		/*
		 printf("Mean fitness = %f stddev = %f sum = %f expval = %f\n", mean, stddev, sum, current_expval);
		 */
	}

	m_pop->select_state++;

	selectval = ran_double(m_pop->selectdata.current_expval) * m_pop->selectdata.mean;

	do
	{
		m_pop->selectdata.marker++;

		if (m_pop->selectdata.marker >= m_pop->orig_size)
			m_pop->selectdata.marker = 0;

		selectval -= m_pop->sorted_organisms[m_pop->selectdata.marker]->fitness;

	} while (selectval > 0.0);

	*m_mother = m_pop->sorted_organisms[m_pop->selectdata.marker];

	selectval = ran_double(m_pop->selectdata.current_expval) * m_pop->selectdata.mean;

	do
	{
		m_pop->selectdata.marker++;

		if (m_pop->selectdata.marker >= m_pop->orig_size)
			m_pop->selectdata.marker = 0;

		selectval -= m_pop->sorted_organisms[m_pop->selectdata.marker]->fitness;

	} while (selectval > 0.0);

	*m_father = m_pop->sorted_organisms[m_pop->selectdata.marker];

	return false;
}


static bool ebex_genetic_select_two_roulette_rebased(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{
	double selectval; /* Select when this reaches zero. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_mother = NULL;

	if (m_pop->orig_size < 1 || m_pop->select_state + 1 > (m_pop->orig_size * m_pop->mutation_ratio))
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		ebex_genetic_select_stats(m_pop, &(m_pop->selectdata.mean), &(m_pop->selectdata.stddev), &(m_pop->selectdata.sum));
		m_pop->selectdata.marker = ran_uint_uniform(m_pop->orig_size);
		m_pop->selectdata.minval = m_pop->sorted_organisms[m_pop->orig_size - 1]->fitness;
		m_pop->selectdata.mean -= m_pop->selectdata.minval;
		if (ISDBL_TINY(m_pop->selectdata.mean))
			die("Degenerate population?");
		m_pop->selectdata.current_expval = (m_pop->selectdata.sum - m_pop->selectdata.minval * m_pop->orig_size)
				/ m_pop->selectdata.mean;
	}

	m_pop->select_state++;

	selectval = ran_double(m_pop->selectdata.current_expval);

	do
	{
		m_pop->selectdata.marker++;

		if (m_pop->selectdata.marker >= m_pop->orig_size)
			m_pop->selectdata.marker = 0;

		selectval -= (m_pop->sorted_organisms[m_pop->selectdata.marker]->fitness - m_pop->selectdata.minval)
				/ m_pop->selectdata.mean;

	} while (selectval > 0.0);

	*m_mother = m_pop->sorted_organisms[m_pop->selectdata.marker];

	selectval = ran_double(m_pop->selectdata.current_expval);

	do
	{
		m_pop->selectdata.marker++;

		if (m_pop->selectdata.marker >= m_pop->orig_size)
			m_pop->selectdata.marker = 0;

		selectval -= (m_pop->sorted_organisms[m_pop->selectdata.marker]->fitness - m_pop->selectdata.minval)
				/ m_pop->selectdata.mean;

	} while (selectval > 0.0);

	*m_father = m_pop->sorted_organisms[m_pop->selectdata.marker];

	return false;
}


/**
 * Stochastic Universal Sampling
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_sus(population_t *m_pop, organism_t **m_parent)
{
	double sum; /* Fitness total. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_parent = NULL;

	if (m_pop->orig_size < 1)
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		m_pop->selectdata.num_to_select = MAX(1, (int) floor(m_pop->orig_size * m_pop->mutation_ratio));
		sum = ebex_genetic_select_sum_fitness(m_pop);
		m_pop->selectdata.step = sum / (m_pop->orig_size * m_pop->mutation_ratio);
		m_pop->selectdata.offset1 = ran_double(m_pop->selectdata.step);
		m_pop->selectdata.current1 = 0;
	}
	else if (m_pop->select_state > m_pop->selectdata.num_to_select)
	{
		return true;
	}
	else
	{
		m_pop->selectdata.offset1 += m_pop->selectdata.step;
	}

	while (m_pop->selectdata.offset1 > m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness)
	{
		m_pop->selectdata.offset1 -= m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness;
		m_pop->selectdata.current1++;
		if (m_pop->selectdata.current1 >= m_pop->orig_size)
			m_pop->selectdata.current1 -= m_pop->orig_size;
	}

	*m_parent = m_pop->sorted_organisms[m_pop->selectdata.current1];

	m_pop->select_state++;

	return false;
}


static bool ebex_genetic_select_two_sus(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{
	double sum; /* Fitness total. */
	int *ordered; /* Ordered indices. */
	int i; /* Loop variable over indices. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_mother = NULL;

	if (m_pop->orig_size < 1)
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		m_pop->selectdata.num_to_select = MAX(1, (int) floor(m_pop->orig_size * m_pop->crossover_ratio));
		sum = ebex_genetic_select_sum_fitness(m_pop);
		m_pop->selectdata.step = sum / m_pop->selectdata.num_to_select;
		m_pop->selectdata.offset1 = m_pop->selectdata.offset2 = ran_double(m_pop->selectdata.step);
		m_pop->selectdata.current1 = 0;
		m_pop->selectdata.current2 = 0;
		m_pop->selectdata.permutation = NULL;

		if (!(m_pop->selectdata.permutation = e_malloc(sizeof(int)*m_pop->orig_size)))
			die("Unable to allocate memory");
		if (!(ordered = e_malloc(sizeof(int)*m_pop->orig_size)))
			die("Unable to allocate memory");
		for (i = 0; i < m_pop->orig_size; i++)
			ordered[i] = i;
		ran_int_permutation(m_pop->orig_size, ordered, m_pop->selectdata.permutation);
		e_free(ordered);
	}
	else if (m_pop->select_state > m_pop->selectdata.num_to_select)
	{
		e_free(m_pop->selectdata.permutation);
		m_pop->selectdata.permutation = NULL;
		return true;
	}
	else
	{
		m_pop->selectdata.offset1 += m_pop->selectdata.step;
		m_pop->selectdata.offset2 += m_pop->selectdata.step;
	}

	while (m_pop->selectdata.offset1 > m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness)
	{
		m_pop->selectdata.offset1 -= m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness;
		m_pop->selectdata.current1++;
		if (m_pop->selectdata.current1 >= m_pop->orig_size)
			m_pop->selectdata.current1 -= m_pop->orig_size;
	}

	while (m_pop->selectdata.offset2 > m_pop->sorted_organisms[m_pop->selectdata.permutation[m_pop->selectdata.current2]]->fitness)
	{
		m_pop->selectdata.offset2 -= m_pop->sorted_organisms[m_pop->selectdata.permutation[m_pop->selectdata.current2]]->fitness;
		m_pop->selectdata.current2++;
		if (m_pop->selectdata.current2 >= m_pop->orig_size)
			m_pop->selectdata.current2 -= m_pop->orig_size;
	}

	*m_mother = m_pop->sorted_organisms[m_pop->selectdata.current1];
	*m_father = m_pop->sorted_organisms[m_pop->selectdata.permutation[m_pop->selectdata.current2]];

	m_pop->select_state++;

	return false;
}

/**
 * Stochastic Universal Sampling with squared fitnesses
 * @param m_pop
 * @param m_parent
 * @return
 */
static bool ebex_genetic_select_one_sussq(population_t *m_pop, organism_t **m_parent)
{
	double sum; /* Fitness total. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_parent = NULL;

	if (m_pop->orig_size < 1)
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		m_pop->selectdata.num_to_select = MAX(1, (int) floor(m_pop->orig_size * m_pop->mutation_ratio));
		sum = ebex_genetic_select_sum_sq_fitness(m_pop);
		m_pop->selectdata.step = sum / (m_pop->orig_size * m_pop->mutation_ratio);
		m_pop->selectdata.offset1 = ran_double(m_pop->selectdata.step);
		m_pop->selectdata.current1 = 0;
	}
	else if (m_pop->select_state > m_pop->selectdata.num_to_select)
	{
		return true;
	}
	else
	{
		m_pop->selectdata.offset1 += m_pop->selectdata.step;
	}

	while (m_pop->selectdata.offset1
			> m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness
					* m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness)
	{
		m_pop->selectdata.offset1 -= (m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness
				* m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness);
		m_pop->selectdata.current1++;
		if (m_pop->selectdata.current1 >= m_pop->orig_size)
			m_pop->selectdata.current1 -= m_pop->orig_size;
	}

	*m_parent = m_pop->sorted_organisms[m_pop->selectdata.current1];

	m_pop->select_state++;

	return false;
}

static bool ebex_genetic_select_two_sussq(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{
	double sum; /* Fitness total. */
	int *ordered; /* Ordered indices. */
	int i; /* Loop variable over indices. */

	if (!m_pop)
		die("Null pointer to population structure passed.");

	*m_mother = NULL;

	if (m_pop->orig_size < 1)
	{
		return true;
	}

	if (m_pop->select_state == 0)
	{ /* First call of this generation. */
		m_pop->selectdata.num_to_select = MAX(1, (int) floor(m_pop->orig_size * m_pop->crossover_ratio));
		sum = ebex_genetic_select_sum_sq_fitness(m_pop);
		m_pop->selectdata.step = sum / m_pop->selectdata.num_to_select;
		m_pop->selectdata.offset1 = m_pop->selectdata.offset2 = ran_double(m_pop->selectdata.step);
		m_pop->selectdata.current1 = 0;
		m_pop->selectdata.current2 = 0;
		m_pop->selectdata.permutation = NULL;

		if (!(m_pop->selectdata.permutation = e_malloc(sizeof(int)*m_pop->orig_size)))
			die("Unable to allocate memory");
		if (!(ordered = e_malloc(sizeof(int)*m_pop->orig_size)))
			die("Unable to allocate memory");
		for (i = 0; i < m_pop->orig_size; i++)
			ordered[i] = i;
		ran_int_permutation(m_pop->orig_size, ordered, m_pop->selectdata.permutation);
		e_free(ordered);
	}
	else if (m_pop->select_state > m_pop->selectdata.num_to_select)
	{
		e_free(m_pop->selectdata.permutation);
		m_pop->selectdata.permutation = NULL;
		return true;
	}
	else
	{
		m_pop->selectdata.offset1 += m_pop->selectdata.step;
		m_pop->selectdata.offset2 += m_pop->selectdata.step;
	}

	while (m_pop->selectdata.offset1
			> m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness
					* m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness)
	{
		m_pop->selectdata.offset1 -= (m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness
				* m_pop->sorted_organisms[m_pop->selectdata.current1]->fitness);
		m_pop->selectdata.current1++;
		if (m_pop->selectdata.current1 >= m_pop->orig_size)
			m_pop->selectdata.current1 -= m_pop->orig_size;
	}

	while (m_pop->selectdata.offset2
			> m_pop->sorted_organisms[m_pop->selectdata.current2]->fitness
					* m_pop->sorted_organisms[m_pop->selectdata.current2]->fitness)
	{
		m_pop->selectdata.offset2 -= (m_pop->sorted_organisms[m_pop->selectdata.current2]->fitness
				* m_pop->sorted_organisms[m_pop->selectdata.current2]->fitness);
		m_pop->selectdata.current2++;
		if (m_pop->selectdata.current2 >= m_pop->orig_size)
			m_pop->selectdata.current2 -= m_pop->orig_size;
	}

	*m_mother = m_pop->sorted_organisms[m_pop->selectdata.current1];
	*m_father = m_pop->sorted_organisms[m_pop->selectdata.permutation[m_pop->selectdata.current2]];

	m_pop->select_state++;

	return false;
}


static bool ebex_genetic_select_one_aggressive(population_t *m_pop, organism_t **m_parent)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_parent = m_pop->sorted_organisms[ran_uint_uniform(1 + m_pop->select_state % (m_pop->orig_size - 1))];

	return m_pop->select_state > (m_pop->orig_size * m_pop->mutation_ratio);
}



static bool ebex_genetic_select_two_aggressive(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_father = m_pop->sorted_organisms[ran_uint_uniform(1 + m_pop->select_state % (m_pop->orig_size - 1))];
	*m_mother = m_pop->sorted_organisms[ran_uint_uniform(1 + m_pop->select_state % (m_pop->orig_size - 1))];

	return m_pop->select_state > (m_pop->orig_size * m_pop->crossover_ratio);
}



static bool ebex_genetic_select_one_best(population_t *m_pop, organism_t **m_parent)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_parent = m_pop->sorted_organisms[0];

	return m_pop->select_state > (m_pop->orig_size * m_pop->mutation_ratio);
}



static bool ebex_genetic_select_two_best(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_mother = m_pop->sorted_organisms[ran_uint_uniform(m_pop->orig_size)];
	*m_father = m_pop->sorted_organisms[0];

	return m_pop->select_state > (m_pop->orig_size * m_pop->crossover_ratio);
}



static bool ebex_genetic_select_one_linearrank(population_t *m_pop, organism_t **m_parent)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_parent = m_pop->sorted_organisms[(int) ((1.0 - sqrt(ran_unit_uniform())) * m_pop->orig_size)];

	return m_pop->select_state > (m_pop->orig_size * m_pop->mutation_ratio);
}



static bool ebex_genetic_select_two_linearrank(population_t *m_pop, organism_t **m_mother, organism_t **m_father)
{

	if (!m_pop)
		die("Null pointer to population structure passed.");

	m_pop->select_state++;

	*m_mother = m_pop->sorted_organisms[(int) ((1.0 - sqrt(ran_unit_uniform())) * m_pop->orig_size)];
	do
	{
		*m_father = m_pop->sorted_organisms[(int) ((1.0 - sqrt(ran_unit_uniform())) * m_pop->orig_size)];
	} while (*m_mother == *m_father);

	return m_pop->select_state > (m_pop->orig_size * m_pop->crossover_ratio);
}

bool ebex_genetic_select_one(population_t *m_pop, organism_t **m_result, e_genetic_select_type m_type)
{
	switch(m_type)
	{
		case genetic_select_type_aggressive:
			return ebex_genetic_select_one_aggressive(m_pop, m_result);
		case genetic_select_type_best:
			return ebex_genetic_select_one_best(m_pop, m_result);
		case genetic_select_type_bestof2:
			return ebex_genetic_select_one_bestof2(m_pop, m_result);
		case genetic_select_type_bestof3:
			return ebex_genetic_select_one_bestof3(m_pop, m_result);
		case genetic_select_type_every:
			return ebex_genetic_select_one_every(m_pop, m_result);
		case genetic_select_type_linear_rank:
			return ebex_genetic_select_one_linearrank(m_pop, m_result);
		case genetic_select_type_random:
			return ebex_genetic_select_one_random(m_pop, m_result);
		case genetic_select_type_random_rank:
			return ebex_genetic_select_one_randomrank(m_pop, m_result);
		case genetic_select_type_roulette:
			return ebex_genetic_select_one_roulette(m_pop, m_result);
		case genetic_select_type_roulette_holland:
			return ebex_genetic_select_one_roulette_rebased(m_pop, m_result);
		case genetic_select_type_stochastic:
			return ebex_genetic_select_one_sus(m_pop, m_result);
		case genetic_select_type_stochastic_seq:
			return ebex_genetic_select_one_sussq(m_pop, m_result);
		default:
			dief("Invalid selection type %d", (int)m_type);
			break;
	}
	return false;
}

bool ebex_genetic_select_two(population_t *m_pop, organism_t **m_result1, organism_t **m_result2, e_genetic_select_type m_type)
{
	switch(m_type)
	{
		case genetic_select_type_aggressive:
			return ebex_genetic_select_two_aggressive(m_pop, m_result1, m_result2);
		case genetic_select_type_best:
			return ebex_genetic_select_two_best(m_pop, m_result1, m_result2);
		case genetic_select_type_bestof2:
			return ebex_genetic_select_two_bestof2(m_pop, m_result1, m_result2);
		case genetic_select_type_bestof3:
			return ebex_genetic_select_two_bestof3(m_pop, m_result1, m_result2);
		case genetic_select_type_every:
			return ebex_genetic_select_two_every(m_pop, m_result1, m_result2);
		case genetic_select_type_linear_rank:
			return ebex_genetic_select_two_linearrank(m_pop, m_result1, m_result2);
		case genetic_select_type_random:
			return ebex_genetic_select_two_random(m_pop, m_result1, m_result2);
		case genetic_select_type_random_rank:
			return ebex_genetic_select_two_randomrank(m_pop, m_result1, m_result2);
		case genetic_select_type_roulette:
			return ebex_genetic_select_two_roulette(m_pop, m_result1, m_result2);
		case genetic_select_type_roulette_holland:
			return ebex_genetic_select_two_roulette_rebased(m_pop, m_result1, m_result2);
		case genetic_select_type_stochastic:
			return ebex_genetic_select_two_sus(m_pop, m_result1, m_result2);
		case genetic_select_type_stochastic_seq:
			return ebex_genetic_select_two_sussq(m_pop, m_result1, m_result2);
		default:
			dief("Invalid selection type %d", (int)m_type);
			break;
	}
	return false;
}
